package edu.baylor.websocket;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

/**
 * A Helper class that contains a lot of helper function
 */
public class Helper {
	public static final String WEB_SOCKET_CHARSET = "UTF-8";
	
	/**
	 * Read one line, does not include \r\n
	 * @param in
	 * @return
	 * @throws IOException
	 */
	public static String readLine(InputStream in) throws IOException {
		ByteArrayOutputStream bts = new ByteArrayOutputStream();
		int last = 0;
		while (true) {
			int b = in.read();
			if (b == -1)
				break;
			if(b != '\r' && b!= '\n')
				bts.write(b);
			if (last == '\r' && b == '\n') {
				break;
			}
			last = b;
		}
		return byteArrayToString(bts.toByteArray());
	}
	
	/**
	 * Write one line
	 * @param out
	 * @param line
	 * @throws IOException
	 */
    public static void writeLine(OutputStream out, String line) throws IOException {
        out.write(line.getBytes(Charset.forName("UTF-8")));
        out.write(0x0D);
        out.write(0x0A);
    }

	/**
	 * Convert byte array to a string
	 * @param bytes
	 * @throws IOException
	 */
    public static String byteArrayToString(byte ... bytes) throws UnsupportedEncodingException {
    	return (new String(bytes, "UTF-8")); 
    }
    
	/**
	 * Convert big-endian byte to long
	 * @param b
	 * @return
	 */
	public static long byteToLong(byte[] b) {
		long l = 0;
		int len = b.length;
		for(int i=0; i<len && i < 8; i++){
			l = (long) l << 8 | byteToUnsignInt(b[i]);
		}
		return l;
	}

	/**
	 * Convert byte to unsigned integer
	 * @param b
	 * @return
	 */
	public static int byteToUnsignInt(byte b) {
		if( b >> 1 == b >>> 1)
			return b;
		else
			return 256 + b;
	}

	/**
	 * Convert big-endian byte to integer
	 * @param b
	 * @return
	 */
	public static int byteToInt(byte ... b) {
		return (int)byteToLong(b);
	}

	/**
	 * Convert big-endian byte to short
	 * @param b
	 * @return
	 */
	public static short byteToShort(byte ...b) {
		return (short)byteToLong(b);
	}

	/**
	 * Convert big-endian byte to short
	 * @param b
	 * @return
	 */
	public static byte[] readFrame(InputStream in) throws IOException {
		return null;
	}
	
	/**
	 * Convert integer to 4 bytes
	 * @param l
	 * @param length
	 * @return
	 */
	public static byte[] intTo4Byte(int i) {
		return numberToByte(i, 4);
	}
	
	/**
	 * Convert short to 4 bytes
	 * @param i
	 * @return
	 */
	public static byte[] shortTo4Byte(int i) {
		return numberToByte(i, 2);
	}

	/**
	 * Convert long to 4 bytes
	 * @param i
	 * @return
	 */
	public static byte[] longTo4Byte(long i) {
		return numberToByte(i, 8);
	}

	/**
	 * Convert to byte from high-order to low-order
	 * @param l
	 * @param length
	 * @return
	 */
	private static byte[] numberToByte(long l, int length) {
		byte[] bts = new byte[length];
		for(int i=0; i<length; i++){
			bts[i] = (byte) (l >> ((length -i - 1) * 8));
		}
		return bts;
	}

	/**
	 * Convert bytes to a base64-encoded string
	 * @param b
	 * @return
	 */
	public static String getBASE64(byte[] b) {
		String s = null;
		if (b != null) {
			s = javax.xml.bind.DatatypeConverter.printBase64Binary(b);
		}
		return s;
	}
	
	/**
	 * Convert a base64-encoded string to bytes
	 * @param s
	 * @return
	 */
	public static byte[] getFromBASE64(String s) {
		byte[] b = null;
		if (s != null) {
			b = javax.xml.bind.DatatypeConverter.parseBase64Binary(s);
		}
		return b;
	}
}